/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.form;
import java.beans.PropertyDescriptor;
import java.beans.PropertyEditor;
import java.io.*;
import java.util.*;
import org.openide.explorer.propertysheet.editors.XMLPropertyEditor;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.nodes.Node;
import org.openide.util.Utilities;
import org.openide.TopManager;
import org.openide.loaders.XMLDataObject;
import org.netbeans.modules.form.compat2.layouts.*;
import org.netbeans.modules.form.forminfo.*;
/**
*
* @author Ian Formanek
*/
public class GandalfPersistenceManager extends PersistenceManager {
public static final String CURRENT_VERSION = "1.0"; // NOI18N
public static final String XML_FORM = "Form"; // NOI18N
public static final String XML_NON_VISUAL_COMPONENTS = "NonVisualComponents"; // NOI18N
public static final String XML_CONTAINER = "Container"; // NOI18N
public static final String XML_COMPONENT = "Component"; // NOI18N
public static final String XML_MENU_COMPONENT = "MenuItem"; // NOI18N
public static final String XML_MENU_CONTAINER = "Menu"; // NOI18N
public static final String XML_LAYOUT = "Layout"; // NOI18N
public static final String XML_CONSTRAINTS = "Constraints"; // NOI18N
public static final String XML_CONSTRAINT = "Constraint"; // NOI18N
public static final String XML_SUB_COMPONENTS = "SubComponents"; // NOI18N
public static final String XML_EVENTS = "Events"; // NOI18N
public static final String XML_EVENT = "EventHandler"; // NOI18N
public static final String XML_PROPERTIES = "Properties"; // NOI18N
public static final String XML_PROPERTY = "Property"; // NOI18N
public static final String XML_SYNTHETIC_PROPERTY = "SyntheticProperty"; // NOI18N
public static final String XML_SYNTHETIC_PROPERTIES = "SyntheticProperties"; // NOI18N
public static final String XML_AUX_VALUES = "AuxValues"; // NOI18N
public static final String XML_AUX_VALUE = "AuxValue"; // NOI18N
public static final String XML_SERIALIZED_PROPERTY_VALUE = "SerializedValue"; // NOI18N
public static final String ATTR_FORM_VERSION = "version"; // NOI18N
public static final String ATTR_FORM_TYPE = "type"; // NOI18N
public static final String ATTR_COMPONENT_NAME = "name"; // NOI18N
public static final String ATTR_COMPONENT_CLASS = "class"; // NOI18N
public static final String ATTR_PROPERTY_NAME = "name"; // NOI18N
public static final String ATTR_PROPERTY_TYPE = "type"; // NOI18N
public static final String ATTR_PROPERTY_EDITOR = "editor"; // NOI18N
public static final String ATTR_PROPERTY_VALUE = "value"; // NOI18N
public static final String ATTR_PROPERTY_PRE_CODE = "preCode"; // NOI18N
public static final String ATTR_PROPERTY_POST_CODE = "postCode"; // NOI18N
public static final String ATTR_EVENT_NAME = "event"; // NOI18N
public static final String ATTR_EVENT_HANDLER = "handler"; // NOI18N
public static final String ATTR_AUX_NAME = "name"; // NOI18N
public static final String ATTR_AUX_VALUE = "value"; // NOI18N
public static final String ATTR_AUX_VALUE_TYPE = "type"; // NOI18N
public static final String ATTR_LAYOUT_CLASS = "class"; // NOI18N
public static final String ATTR_CONSTRAINT_LAYOUT = "layoutClass"; // NOI18N
public static final String ATTR_CONSTRAINT_VALUE = "value"; // NOI18N
private static final String ONE_INDENT = " "; // NOI18N
private static final Object NO_VALUE = new Object ();
private org.w3c.dom.Document topDocument = XMLDataObject.createDocument();
/** A method which allows the persistence manager to provide infotrmation on whether
* is is capable to store info about advanced features provided from Developer 3.0
* - all persistence managers except the one providing backward compatibility with
* Developer 2.X should return true from this method.
* @return true if this PersistenceManager is capable to store advanced form features, false otherwise
*/
public boolean supportsAdvancedFeatures () {
return true;
}
/** A method which allows the persistence manager to check whether it can read
* given form format.
* @return true if this PersistenceManager can load form stored in the specified form, false otherwise
* @exception IOException if any problem occured when accessing the form
*/
public boolean canLoadForm (FormDataObject formObject) throws IOException {
FileObject formFile = formObject.getFormEntry ().getFile ();
try {
org.w3c.dom.Document doc = org.openide.loaders.XMLDataObject.parse (formFile.getURL ());
} catch (IOException e) { // [PENDING - just test whether it is an XML file and in this case return false
return false;
} catch (org.xml.sax.SAXException e) { // [PENDING - just test whether it is an XML file and in this case return false
return false;
}
return true;
}
private String readEncoding (InputStream is) {
// If all else fails, assume XML without a declaration, and
// using UTF-8 encoding.
String useEncoding = "UTF-8"; // NOI18N
byte buf [];
int len;
buf = new byte [4];
// See if we can figure out the character encoding used
// in this file by peeking at the first few bytes.
try {
len = is.read (buf);
if (len == 4) switch (buf [0] & 0x0ff) {
case 0:
// 00 3c 00 3f == illegal UTF-16 big-endian
if (buf [1] == 0x3c && buf [2] == 0x00 && buf [3] == 0x3f) {
useEncoding = "UnicodeBig"; // NOI18N
}
// else it's probably UCS-4
break;
case '<': // 0x3c: the most common cases!
switch (buf [1] & 0x0ff) {
// First character is '<'; could be XML without
// an XML directive such as "<hello>", "<!-- ...", // NOI18N
// and so on.
default:
break;
// 3c 00 3f 00 == illegal UTF-16 little endian
case 0x00:
if (buf [2] == 0x3f && buf [3] == 0x00) {
useEncoding = "UnicodeLittle"; // NOI18N
}
// else probably UCS-4
break;
// 3c 3f 78 6d == ASCII and supersets '<?xm'
case '?':
if (buf [2] != 'x' || buf [3] != 'm')
break;
//
// One of several encodings could be used:
// Shift-JIS, ASCII, UTF-8, ISO-8859-*, etc
//
useEncoding = "UTF8"; // NOI18N
}
break;
// 4c 6f a7 94 ... some EBCDIC code page
case 0x4c:
if (buf [1] == 0x6f
&& (0x0ff & buf [2]) == 0x0a7
&& (0x0ff & buf [3]) == 0x094) {
useEncoding = "CP037"; // NOI18N
}
// whoops, treat as UTF-8
break;
// UTF-16 big-endian
case 0xfe:
if ((buf [1] & 0x0ff) != 0xff) break;
useEncoding = "UTF-16"; // NOI18N
// UTF-16 little-endian
case 0xff:
if ((buf [1] & 0x0ff) != 0xfe) break;
useEncoding = "UTF-16"; // NOI18N
// default ... no XML declaration
default:
break;
}
byte buffer[] = new byte [1024];
is.read(buffer);
String s = new String (buffer, useEncoding);
int pos = s.indexOf("encoding"); // NOI18N
String result=null;
int startPos, endPos;
if ((pos > 0) && (pos < s.indexOf (">"))) { // NOI18N
if ( (startPos = s.indexOf('"', pos)) > 0 &&
(endPos = s.indexOf('"', startPos+1)) > startPos ) {
result = s.substring(startPos+1, endPos);
}
}
if (result == null) {
// encoding not specified in xml
//result = System.getProperty ("file.encoding");
result = null;
}
return result;
} catch (java.io.IOException e) {
e.printStackTrace();
return null;
}
}
/** Called to actually load the form stored in specified formObject.
* @param formObject the FormDataObject which represents the form files
* @return the FormManager2 representing the loaded form or null if some problem occured
* @exception IOException if any problem occured when loading the form
*/
public FormManager2 loadForm (FormDataObject formObject) throws IOException {
FileObject formFile = formObject.getFormEntry ().getFile ();
org.w3c.dom.Document doc;
org.w3c.dom.Element mainElement;
String encoding;
try {
encoding = readEncoding (formFile.getURL ().openStream ());
doc = org.openide.loaders.XMLDataObject.parse (formFile.getURL ());
mainElement = doc.getDocumentElement ();
} catch (org.xml.sax.SAXException e) {
throw new IOException (e.getMessage());
}
// walkTree (mainElement, ""); // NOI18N
// A. Do various checks
// 1. check the top-level element name
if (!XML_FORM.equals (mainElement.getTagName ())) {
throw new IOException (FormEditor.getFormBundle ().getString ("ERR_BadXMLFormat"));
}
// 2. check the form version
if (!CURRENT_VERSION.equals (mainElement.getAttribute (ATTR_FORM_VERSION))) {
throw new IOException (FormEditor.getFormBundle ().getString ("ERR_BadXMLVersion"));
}
String infoClass = mainElement.getAttribute (ATTR_FORM_TYPE);
FormInfo formInfo = null;
if (infoClass == null) {
return null;
}
try {
formInfo = (FormInfo) loadClass(infoClass).newInstance ();
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
throw new IOException (java.text.MessageFormat.format (
FormEditor.getFormBundle ().getString ("FMT_ERR_FormInfoNotFound"),
new String[] { infoClass }
)
);
}
RADForm radForm = new RADForm (formInfo);
FormManager2 formManager2 = new FormManager2 (formObject, radForm);
formManager2.setEncoding (encoding);
RADVisualContainer topComp = (RADVisualContainer)radForm.getTopLevelComponent (); // [PENDING - illegal cast]
// B. process top-element's subnodes (all required)
org.w3c.dom.NodeList childNodes = mainElement.getChildNodes ();
if (childNodes == null) {
throw new IOException (FormEditor.getFormBundle ().getString ("ERR_BadXMLFormat"));
}
loadNonVisuals (mainElement, formManager2);
loadContainer (mainElement, formManager2, topComp, null);
return formManager2;
}
private boolean loadNonVisuals (org.w3c.dom.Node node, FormManager2 formManager2) {
org.w3c.dom.Node nonVisualsNode = findSubNode (node, XML_NON_VISUAL_COMPONENTS);
org.w3c.dom.NodeList childNodes = (nonVisualsNode == null) ? null : nonVisualsNode.getChildNodes ();
// System.out.println ("NonVisual children: "+childNodes); // NOI18N
ArrayList list = new ArrayList ();
if (childNodes != null) {
// System.out.println ("NonVisual children len: "+childNodes.getLength ()); // NOI18N
for (int i = 0; i < childNodes.getLength (); i++) {
if (childNodes.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
// System.out.println ("Processing node: "+childNodes.item (i).getNodeName ()); // NOI18N
if (XML_COMPONENT.equals (childNodes.item (i).getNodeName ())) {
RADComponent comp = new RADComponent ();
if (loadComponent (childNodes.item (i), formManager2, comp, null)) {
list.add (comp);
}
} else if (XML_CONTAINER.equals (childNodes.item (i).getNodeName ())) {
RADContainer cont = new RADContainer ();
if (loadContainer (childNodes.item (i), formManager2, cont, null)) {
list.add (cont);
}
} else if (XML_MENU_COMPONENT.equals (childNodes.item (i).getNodeName ())) {
// System.out.println ("$$$MenuItem"); // NOI18N
RADMenuItemComponent comp = new RADMenuItemComponent ();
if (loadComponent (childNodes.item (i), formManager2, comp, null)) {
list.add (comp);
}
} else if (XML_MENU_CONTAINER.equals (childNodes.item (i).getNodeName ())) {
// System.out.println ("$$$Menu"); // NOI18N
RADMenuComponent cont = new RADMenuComponent ();
if (loadContainer (childNodes.item (i), formManager2, cont, null)) {
list.add (cont);
}
}
}
}
RADComponent[] nonVisualComps = new RADComponent[list.size ()];
list.toArray (nonVisualComps);
formManager2.initNonVisualComponents (nonVisualComps);
return true;
}
private boolean loadComponent (org.w3c.dom.Node node, FormManager2 formManager2, RADComponent comp, ComponentContainer parentContainer) {
try {
if (!(comp instanceof FormContainer)) {
comp.initialize (formManager2);
String className = findAttribute (node, ATTR_COMPONENT_CLASS);
String compName = findAttribute (node, ATTR_COMPONENT_NAME);
Class compClass = null;
try {
compClass = loadClass (className);
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
FormEditor.fileError (java.text.MessageFormat.format (
FormEditor.getFormBundle ().getString ("FMT_ERR_ClassNotFound"),
new Object [] {
e.getMessage (),
e.getClass ().getName (),
}
), e);
return false; // failed to load the component!!!
}
comp.setComponent (compClass);
comp.setName (compName);
}
org.w3c.dom.NodeList childNodes = node.getChildNodes ();
if (childNodes != null) {
for (int i = 0; i < childNodes.getLength (); i++) {
org.w3c.dom.Node componentNode = childNodes.item (i);
if (componentNode.getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (XML_PROPERTIES.equals (componentNode.getNodeName ())) {
loadProperties (componentNode, comp);
} else if (XML_EVENTS.equals (componentNode.getNodeName ())) {
Hashtable events = loadEvents (componentNode);
if (events != null) {
comp.initDeserializedEvents (events);
}
} else if (XML_AUX_VALUES.equals (componentNode.getNodeName ())) {
HashMap auxValues = loadAuxValues (componentNode);
if (auxValues != null) {
for (Iterator it = auxValues.keySet ().iterator (); it.hasNext (); ) {
String auxName = (String)it.next ();
comp.setAuxValue (auxName, auxValues.get (auxName));
}
}
} else if (XML_SYNTHETIC_PROPERTIES.equals (componentNode.getNodeName ())) {
loadSyntheticProperties (componentNode, comp);
}
}
}
return true;
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
return false; // [PENDING - undo already processed init?]
}
}
private boolean loadVisualComponent (org.w3c.dom.Node node, FormManager2 formManager2, RADVisualComponent comp, ComponentContainer parentContainer) {
if (!loadComponent (node, formManager2, comp, parentContainer)) {
return false;
}
if (!(comp instanceof FormContainer)) {
org.w3c.dom.Node constraintsNode = findSubNode (node, XML_CONSTRAINTS);
if (constraintsNode != null) {
org.w3c.dom.Node[] constrNodes = findSubNodes (constraintsNode, XML_CONSTRAINT);
for (int i = 0; i < constrNodes.length; i++) {
String layoutName = findAttribute (constrNodes[i], ATTR_CONSTRAINT_LAYOUT);
String cdName = findAttribute (constrNodes[i], ATTR_CONSTRAINT_VALUE);
if ((layoutName != null) && (cdName != null)) {
try {
Class layoutClass = loadClass (layoutName);
DesignLayout.ConstraintsDescription cd = (DesignLayout.ConstraintsDescription) loadClass (cdName).newInstance ();
org.w3c.dom.NodeList children = constrNodes[i].getChildNodes ();
if (children != null) {
for (int j = 0; j < children.getLength (); j++) {
if (children.item (j).getNodeType () == org.w3c.dom.Node.ELEMENT_NODE) {
cd.readFromXML (children.item (j));
break;
}
}
}
comp.setConstraints (layoutClass, cd);
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore and try another constraints // [PENDING - add to errors list]
}
}
}
}
}
return true;
}
private boolean loadContainer (org.w3c.dom.Node node, FormManager2 formManager2, RADComponent comp, ComponentContainer parentContainer) {
if (comp instanceof RADVisualComponent) {
if (!loadVisualComponent (node, formManager2, (RADVisualComponent)comp, parentContainer)) return false;
} else {
if (!loadComponent (node, formManager2, comp, parentContainer)) return false;
}
// System.out.println ("1..."); // NOI18N
if (comp instanceof ComponentContainer) {
// System.out.println ("2..."); // NOI18N
org.w3c.dom.Node subCompsNode = findSubNode (node, XML_SUB_COMPONENTS);
org.w3c.dom.NodeList children = null;
if (subCompsNode != null) children = subCompsNode.getChildNodes ();
// System.out.println ("3..."); // NOI18N
if (children != null) {
// System.out.println ("4..."); // NOI18N
ArrayList list = new ArrayList ();
for (int i = 0; i < children.getLength (); i++) {
org.w3c.dom.Node componentNode = children.item (i);
// System.out.println ("Processing node: "+componentNode.getNodeName ()); // NOI18N
if (componentNode.getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (XML_COMPONENT.equals (componentNode.getNodeName ())) { // [PENDING - visual x non-visual]
RADVisualComponent newComp = new RADVisualComponent ();
if (loadVisualComponent (componentNode, formManager2, newComp, (ComponentContainer)comp)) {
list.add (newComp);
}
} else if (XML_MENU_COMPONENT.equals (componentNode.getNodeName ())) { // [PENDING - visual x non-visual]
RADMenuItemComponent newComp = new RADMenuItemComponent ();
// System.out.println ("Processing menu node: "+componentNode.getNodeName ()); // NOI18N
if (loadContainer (componentNode, formManager2, newComp, (ComponentContainer)comp)) {
list.add (newComp);
}
} else if (XML_MENU_CONTAINER.equals (componentNode.getNodeName ())) { // [PENDING - visual x non-visual]
RADMenuComponent newComp = new RADMenuComponent ();
// System.out.println ("Processing menu container node: "+componentNode.getNodeName ()); // NOI18N
if (loadContainer (componentNode, formManager2, newComp, (ComponentContainer)comp)) {
list.add (newComp);
}
} else {
RADVisualContainer newComp = new RADVisualContainer ();
if (loadContainer (componentNode, formManager2, newComp, (ComponentContainer)comp)) {
list.add (newComp);
}
}
}
RADComponent[] childComps = new RADComponent[list.size ()];
list.toArray (childComps);
((ComponentContainer)comp).initSubComponents (childComps);
} else {
((ComponentContainer)comp).initSubComponents (new RADComponent[0]);
}
}
if (comp instanceof RADVisualContainer) {
org.w3c.dom.Node layoutNode = findSubNode (node, XML_LAYOUT);
String className = findAttribute (layoutNode, ATTR_LAYOUT_CLASS);
try {
DesignLayout dl = (DesignLayout) loadClass (className).newInstance ();
org.w3c.dom.Node[] propNodes = findSubNodes (layoutNode, XML_PROPERTY);
if (propNodes.length > 0) {
HashMap propsMap = new HashMap (propNodes.length * 2);
for (int i = 0; i < propNodes.length; i++) {
try {
Object propValue = getEncodedPropertyValue (propNodes[i], null);
String propName = findAttribute (propNodes[i], ATTR_PROPERTY_NAME);
if ((propName != null) && (propValue != null) && (propValue != NO_VALUE)) {
propsMap.put (propName, propValue);
}
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore property with problem
// [PENDING - notify problem]
}
}
dl.initChangedProperties (propsMap);
}
((RADVisualContainer)comp).setDesignLayout (dl);
} catch (Exception e) {
// if (System.getProperty ("netbeans.debug.exceptions") != null) // [PENDING]
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
return false; // [PENDING - notify]
}
}
return true;
}
private void loadProperties (org.w3c.dom.Node node, RADComponent comp) {
org.w3c.dom.Node[] propNodes = findSubNodes (node, XML_PROPERTY);
if (propNodes.length > 0) {
for (int i = 0; i < propNodes.length; i++) {
Object propValue;
try {
propValue = getEncodedPropertyValue (propNodes[i], comp);
if (propValue == NO_VALUE) {
// the value was not saved, just the pre/post code, which was already set inside the getEncodedPropertyValue method
continue;
}
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// [PENDING - notify error]
continue; // ignore this property
}
String propName = findAttribute (propNodes[i], ATTR_PROPERTY_NAME);
String propType = findAttribute (propNodes[i], ATTR_PROPERTY_TYPE);
RADComponent.RADProperty prop = comp.getPropertyByName (propName);
String propertyEditor = findAttribute (propNodes[i], ATTR_PROPERTY_EDITOR);
if (propertyEditor != null) {
try {
Class editorClass = loadClass (propertyEditor);
Class propertyClass = findPropertyType (propType);
PropertyEditor ed = FormEditor.createPropertyEditor (editorClass, propertyClass, comp, prop);
((RADComponent.RADProperty)prop).setCurrentEditor (ed);
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore
}
}
try {
prop.setValue (propValue);
} catch (java.lang.reflect.InvocationTargetException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore this property // [PENDING]
} catch (IllegalAccessException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore this property // [PENDING]
} catch (Exception e) {
// unexpected exception - always printed
e.printStackTrace ();
// ignore this property
}
}
}
}
private void loadSyntheticProperties (org.w3c.dom.Node node, RADComponent comp) {
org.w3c.dom.Node[] propNodes = findSubNodes (node, XML_SYNTHETIC_PROPERTY);
if (propNodes.length > 0) {
for (int i = 0; i < propNodes.length; i++) {
String propName = findAttribute (propNodes[i], ATTR_PROPERTY_NAME);
String encodedValue = findAttribute (propNodes[i], ATTR_PROPERTY_VALUE);
String propType = findAttribute (propNodes[i], ATTR_PROPERTY_TYPE);
Class propClass = null;
try {
if (propType != null) propClass = findPropertyType (propType);
} catch (Exception e2) {
// OK, try to use decodeValue in this case
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e2.printStackTrace (); // NOI18N
}
Object propValue=null;
//System.out.println("loading name="+propName+", encodedValue="+encodedValue); // NOI18N
try {
if (propClass != null) {
try {
propValue = decodePrimitiveValue (encodedValue, propClass);
} catch (IllegalArgumentException e) {
// not a primitive type
propValue = decodeValue (encodedValue);
}
} else { // info about the property type was not saved
propValue = decodeValue (encodedValue);
}
} catch (IOException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// [PENDING - handle error]
}
//System.out.println("......encoded to:"+propValue); // NOI18N
Node.Property [] props = comp.getSyntheticProperties ();
Node.Property prop=null;
for (int j=0, n=props.length; j<n; j++) {
if (props[j].getName ().equals (propName)) {
prop = props [j];
break;
}
}
if (prop == null) // unknown property, ignore
continue;
try {
prop.setValue (propValue);
} catch (java.lang.reflect.InvocationTargetException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore this property // [PENDING]
} catch (IllegalAccessException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// ignore this property // [PENDING]
} catch (Exception e) {
// unexpected exception - always printed
e.printStackTrace ();
// ignore this property
}
}
}
}
private Hashtable loadEvents (org.w3c.dom.Node node) {
Hashtable eventsTable = new Hashtable (20);
org.w3c.dom.NodeList children = node.getChildNodes ();
if (children != null) {
for (int i = 0; i < children.getLength (); i++) {
if (children.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (XML_EVENT.equals (children.item (i).getNodeName ())) {
String eventName = findAttribute (children.item (i), ATTR_EVENT_NAME);
String handlerName = findAttribute (children.item (i), ATTR_EVENT_HANDLER);
if ((eventName != null) && (handlerName != null)) { // [PENDING - error check]
eventsTable.put (eventName, handlerName);
}
}
}
}
return eventsTable;
}
private HashMap loadAuxValues (org.w3c.dom.Node node) {
HashMap auxTable = new HashMap (20);
org.w3c.dom.NodeList children = node.getChildNodes ();
if (children != null) {
for (int i = 0; i < children.getLength (); i++) {
if (children.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (XML_AUX_VALUE.equals (children.item (i).getNodeName ())) {
String auxName = findAttribute (children.item (i), ATTR_AUX_NAME);
String auxValue = findAttribute (children.item (i), ATTR_AUX_VALUE);
String auxValueClass = findAttribute (children.item (i), ATTR_AUX_VALUE_TYPE);
if ((auxName != null) && (auxValue != null)) { // [PENDING - error check]
try {
Object auxValueDecoded = null;
Class auxValueType = null;
if (auxValueClass != null) {
try {
auxValueType = findPropertyType (auxValueClass);
} catch (Exception e2) {
// OK, try to use decodeValue in this case
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e2.printStackTrace (); // NOI18N
}
}
if (auxValueType != null) {
try {
auxValueDecoded = decodePrimitiveValue (auxValue, auxValueType);
} catch (IllegalArgumentException e3) {
// not decoded as primitive value
auxValueDecoded = decodeValue (auxValue);
}
} else {
// info about property class not stored
auxValueDecoded = decodeValue (auxValue);
}
auxTable.put (auxName, auxValueDecoded);
} catch (IOException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// [PENDING - handle error]
}
}
}
}
}
return auxTable;
}
/** Called to actually save the form represented by specified FormManager2 into specified formObject.
* @param formObject the FormDataObject which represents the form files
* @param manager the FormManager2 representing the form to be saved
* @exception IOException if any problem occured when saving the form
*/
public void saveForm (FormDataObject formObject, FormManager2 manager) throws IOException {
FileObject formFile = formObject.getFormEntry ().getFile ();
FileLock lock = null;
java.io.OutputStream os = null;
String encoding = manager.getEncoding();
if (encoding == null) {
encoding = "UTF-8";
}
else {
// XXX(-tdt) test if the encoding is supported by the JDK
try {
String x = new String(new byte[0], 0, 0, encoding);
}
catch (java.io.UnsupportedEncodingException ex) {
encoding = "UTF-8";
}
}
try {
lock = formFile.lock ();
StringBuffer buf = new StringBuffer ();
// 1.store XML file header
buf.append ("<?xml version=\"1.0\""); // NOI18N
buf.append (" encoding=\"" + encoding + "\""); // NOI18N
buf.append (" ?>\n"); // NOI18N
buf.append ("\n"); // NOI18N
// 2.store Form element
addElementOpenAttr (
buf,
XML_FORM,
new String[] { ATTR_FORM_VERSION, ATTR_FORM_TYPE },
new String[] { CURRENT_VERSION, manager.getRADForm ().getFormInfo ().getClass ().getName () }
);
// 3.store Non-Visual Components
RADComponent[] nonVisuals = manager.getNonVisualComponents ();
if (nonVisuals.length > 0) {
buf.append (ONE_INDENT); addElementOpen (buf, XML_NON_VISUAL_COMPONENTS);
for (int i = 0; i < nonVisuals.length; i++) {
String elementType;
if (nonVisuals[i] instanceof RADMenuComponent) elementType = XML_MENU_CONTAINER;
else if (nonVisuals[i] instanceof RADMenuItemComponent) elementType = XML_MENU_COMPONENT;
else if (nonVisuals[i] instanceof ComponentContainer) elementType = XML_CONTAINER;
else elementType = XML_COMPONENT;
buf.append (ONE_INDENT + ONE_INDENT);
addElementOpenAttr (
buf,
elementType,
new String[] { ATTR_COMPONENT_CLASS, ATTR_COMPONENT_NAME },
new String[] { nonVisuals[i].getBeanClass ().getName (), nonVisuals[i].getName () }
);
if (nonVisuals[i] instanceof RADMenuItemComponent) {
saveMenuComponent ((RADMenuItemComponent)nonVisuals[i], buf, ONE_INDENT + ONE_INDENT + ONE_INDENT);
} else if (nonVisuals[i] instanceof ComponentContainer) {
saveContainer ((ComponentContainer)nonVisuals[i], buf, ONE_INDENT + ONE_INDENT + ONE_INDENT);
} else {
saveComponent (nonVisuals[i], buf, ONE_INDENT + ONE_INDENT + ONE_INDENT);
}
buf.append (ONE_INDENT + ONE_INDENT); addElementClose (buf, elementType);
}
buf.append (ONE_INDENT); addElementClose (buf, XML_NON_VISUAL_COMPONENTS);
}
// 4.store form and its visual components hierarchy
saveContainer ((ComponentContainer)manager.getRADForm ().getTopLevelComponent (), buf, ONE_INDENT);
addElementClose (buf, XML_FORM);
os = formFile.getOutputStream (lock); // [PENDING - first save to ByteArray for safety]
os.write (buf.toString ().getBytes(encoding));
} finally {
if (os != null) os.close ();
if (lock != null) lock.releaseLock ();
}
}
private void saveContainer (ComponentContainer container, StringBuffer buf, String indent) {
if (container instanceof RADVisualContainer) {
saveVisualComponent ((RADVisualComponent)container, buf, indent);
saveLayout (((RADVisualContainer)container).getDesignLayout (), buf, indent);
} else {
saveComponent ((RADComponent)container, buf, indent);
}
RADComponent[] children = container.getSubBeans ();
if (children.length > 0) {
buf.append (indent); addElementOpen (buf, XML_SUB_COMPONENTS);
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof ComponentContainer) {
buf.append (indent + ONE_INDENT);
addElementOpenAttr (
buf,
XML_CONTAINER,
new String[] { ATTR_COMPONENT_CLASS, ATTR_COMPONENT_NAME },
new String[] { children[i].getBeanClass ().getName (), children[i].getName () }
);
saveContainer ((ComponentContainer)children[i], buf, indent + ONE_INDENT + ONE_INDENT);
buf.append (indent + ONE_INDENT); addElementClose (buf, XML_CONTAINER);
} else {
buf.append (indent + ONE_INDENT);
addElementOpenAttr (
buf,
XML_COMPONENT,
new String[] { ATTR_COMPONENT_CLASS, ATTR_COMPONENT_NAME },
new String[] { children[i].getBeanClass ().getName (), children[i].getName () }
);
if (children[i] instanceof RADVisualComponent) {
saveVisualComponent ((RADVisualComponent)children[i], buf, indent + ONE_INDENT + ONE_INDENT);
} else {
saveComponent (children[i], buf, indent + ONE_INDENT + ONE_INDENT);
}
buf.append (indent + ONE_INDENT); addElementClose (buf, XML_COMPONENT);
}
}
buf.append (indent); addElementClose (buf, XML_SUB_COMPONENTS);
}
}
private void saveLayout (DesignLayout layout, StringBuffer buf, String indent) {
buf.append ("\n"); // NOI18N
buf.append (indent);
List changedProperties = layout.getChangedProperties ();
if (changedProperties.size () == 0) {
addLeafElementOpenAttr (
buf,
XML_LAYOUT,
new String[] { ATTR_LAYOUT_CLASS },
new String[] { layout.getClass ().getName () }
);
} else {
addElementOpenAttr (
buf,
XML_LAYOUT,
new String[] { ATTR_LAYOUT_CLASS },
new String[] { layout.getClass ().getName () }
);
for (Iterator it = changedProperties.iterator (); it.hasNext (); ) {
Node.Property prop = (Node.Property)it.next ();
String propertyName = prop.getName ();
Object value = null;
try {
value = prop.getValue ();
} catch (java.lang.reflect.InvocationTargetException e) {
continue; // ignore this property
} catch (IllegalAccessException e) {
continue; // ignore this property
}
PropertyEditor ed = prop.getPropertyEditor ();
String encodedValue = null;
String encodedSerializeValue = null;
org.w3c.dom.Node valueNode = null;
if (ed instanceof XMLPropertyEditor) {
ed.setValue (value);
valueNode = ((XMLPropertyEditor)ed).storeToXML (topDocument);
if (valueNode == null) continue; // editor refused to save the value
} else {
encodedValue = encodePrimitiveValue (value);
if (encodedValue == null) encodedSerializeValue = encodeValue (value);
if ((encodedValue == null) && (encodedSerializeValue == null)) {
// [PENDING - notify problem?]
continue;
}
}
buf.append (indent + ONE_INDENT);
if (encodedValue != null) {
addLeafElementOpenAttr (
buf,
XML_PROPERTY,
new String[] { ATTR_PROPERTY_NAME, ATTR_PROPERTY_TYPE, ATTR_PROPERTY_VALUE },
new String[] { propertyName, prop.getValueType ().getName (), encodedValue }
);
} else {
addElementOpenAttr (
buf,
XML_PROPERTY,
new String[] {
ATTR_PROPERTY_NAME,
ATTR_PROPERTY_TYPE,
ATTR_PROPERTY_EDITOR,
},
new String[] {
prop.getName (),
prop.getValueType ().getName (),
ed.getClass ().getName (),
}
);
if (valueNode != null) {
saveNodeIntoText (buf, valueNode, indent + ONE_INDENT);
} else {
addLeafElementOpenAttr (
buf,
XML_SERIALIZED_PROPERTY_VALUE,
new String[] {
ATTR_PROPERTY_VALUE,
},
new String[] {
encodedSerializeValue,
}
);
}
buf.append (indent);
addElementClose (buf, XML_PROPERTY);
}
}
buf.append (indent); addElementClose (buf, XML_LAYOUT);
}
}
private void saveVisualComponent (RADVisualComponent component, StringBuffer buf, String indent) {
saveComponent (component, buf, indent);
if (!(component instanceof FormContainer)) {
buf.append (indent); addElementOpen (buf, XML_CONSTRAINTS);
saveConstraints (component, buf, indent + ONE_INDENT);
buf.append (indent); addElementClose (buf, XML_CONSTRAINTS);
}
}
private void saveMenuComponent (RADMenuItemComponent component, StringBuffer buf, String indent) {
saveComponent (component, buf, indent);
if (component instanceof RADMenuComponent) {
RADComponent[] children = ((RADMenuComponent)component).getSubBeans ();
if (children.length > 0) {
buf.append (indent); addElementOpen (buf, XML_SUB_COMPONENTS);
for (int i = 0; i < children.length; i++) {
String elementType;
if (children[i] instanceof RADMenuComponent) elementType = XML_MENU_CONTAINER;
else if (children[i] instanceof RADMenuItemComponent) elementType = XML_MENU_COMPONENT;
else elementType = XML_COMPONENT;
buf.append (indent + ONE_INDENT);
addElementOpenAttr (
buf,
elementType,
new String[] { ATTR_COMPONENT_CLASS, ATTR_COMPONENT_NAME },
new String[] { children[i].getBeanClass ().getName (), children[i].getName () }
);
// [PENDING - RADComponents which are not menu???]
saveMenuComponent ((RADMenuItemComponent)children[i], buf, indent + ONE_INDENT + ONE_INDENT);
buf.append (indent + ONE_INDENT); addElementClose (buf, elementType);
}
buf.append (indent); addElementClose (buf, XML_SUB_COMPONENTS);
}
}
}
private void saveComponent (RADComponent component, StringBuffer buf, String indent) {
// 1. Properties
boolean doSaveProps = false;
RADComponent.RADProperty[] props = component.getAllProperties ();
for (int i = 0; i < props.length; i++) {
if (props[i].isChanged () || (props[i].getPreCode () != null) || (props[i].getPostCode () != null)) {
doSaveProps = true;
break;
}
}
if (doSaveProps) {
buf.append (indent); addElementOpen (buf, XML_PROPERTIES);
saveProperties (component, buf, indent + ONE_INDENT);
buf.append (indent); addElementClose (buf, XML_PROPERTIES);
}
// 1.a synthetic properties - only for RADVisualFormContainer
if (component instanceof RADVisualFormContainer) {
buf.append (indent); addElementOpen (buf, XML_SYNTHETIC_PROPERTIES);
saveSyntheticProperties (component, buf, indent + ONE_INDENT);
buf.append (indent); addElementClose (buf, XML_SYNTHETIC_PROPERTIES);
}
// 2. Events
if (component.getEventsList ().getEventNames ().size () > 0) {
buf.append ("\n"); // NOI18N
buf.append (indent); addElementOpen (buf, XML_EVENTS);
saveEvents (component.getEventsList ().getEventNames (), buf, indent + ONE_INDENT);
buf.append (indent); addElementClose (buf, XML_EVENTS);
}
// 3. Aux Values
if (component.getAuxValues ().size () > 0) {
buf.append ("\n"); // NOI18N
buf.append (indent); addElementOpen (buf, XML_AUX_VALUES);
saveAuxValues (component.getAuxValues (), buf, indent + ONE_INDENT);
buf.append (indent); addElementClose (buf, XML_AUX_VALUES);
}
}
private void saveProperties (RADComponent component, StringBuffer buf, String indent) {
RADComponent.RADProperty[] props = component.getAllProperties ();
for (int i = 0; i < props.length; i++) {
RADComponent.RADProperty prop = (RADComponent.RADProperty) props[i];
PropertyDescriptor desc = prop.getPropertyDescriptor ();
if (!props[i].isChanged ()) {
if ((props[i].getPreCode () != null) || (props[i].getPreCode () != null)) {
buf.append (indent);
// in this case save only the pre/post code
addLeafElementOpenAttr (
buf,
XML_PROPERTY,
new String[] {
ATTR_PROPERTY_NAME,
ATTR_PROPERTY_PRE_CODE,
ATTR_PROPERTY_POST_CODE,
},
new String[] {
desc.getName (),
prop.getPreCode (),
prop.getPostCode (),
}
);
}
continue; // not changed, so do not save value
}
Object value = null;
try {
value = prop.getValue ();
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// problem getting value => ignore this property
continue;
}
String encodedValue = null;
String encodedSerializeValue = null;
org.w3c.dom.Node valueNode = null;
if (prop.getCurrentEditor () instanceof XMLPropertyEditor) {
prop.getCurrentEditor ().setValue (value);
valueNode = ((XMLPropertyEditor)prop.getCurrentEditor ()).storeToXML (topDocument);
if (valueNode == null) continue; // property editor refused to save the value
} else {
encodedValue = encodePrimitiveValue (value);
if (encodedValue == null) encodedSerializeValue = encodeValue (value);
if ((encodedValue == null) && (encodedSerializeValue == null)) {
// [PENDING - notify problem?]
continue;
}
}
buf.append (indent);
if (encodedValue != null) {
addLeafElementOpenAttr (
buf,
XML_PROPERTY,
new String[] {
ATTR_PROPERTY_NAME,
ATTR_PROPERTY_TYPE,
ATTR_PROPERTY_EDITOR,
ATTR_PROPERTY_VALUE,
ATTR_PROPERTY_PRE_CODE,
ATTR_PROPERTY_POST_CODE,
},
new String[] {
desc.getName (),
desc.getPropertyType ().getName (),
prop.getCurrentEditor ().getClass ().getName (),
encodedValue,
prop.getPreCode (),
prop.getPostCode (),
}
);
} else {
addElementOpenAttr (
buf,
XML_PROPERTY,
new String[] {
ATTR_PROPERTY_NAME,
ATTR_PROPERTY_TYPE,
ATTR_PROPERTY_EDITOR,
ATTR_PROPERTY_PRE_CODE,
ATTR_PROPERTY_POST_CODE,
},
new String[] {
desc.getName (),
desc.getPropertyType ().getName (),
prop.getCurrentEditor ().getClass ().getName (),
prop.getPreCode (),
prop.getPostCode (),
}
);
if (valueNode != null) {
saveNodeIntoText (buf, valueNode, indent + ONE_INDENT);
} else {
buf.append (indent + ONE_INDENT);
addLeafElementOpenAttr (
buf,
XML_SERIALIZED_PROPERTY_VALUE,
new String[] {
ATTR_PROPERTY_VALUE,
},
new String[] {
encodedSerializeValue,
}
);
}
buf.append (indent);
addElementClose (buf, XML_PROPERTY);
}
}
}
private void saveSyntheticProperties (RADComponent component, StringBuffer buf, String indent) {
Node.Property[] props = component.getSyntheticProperties ();
for (int i = 0; i < props.length; i++) {
Node.Property prop = props[i];
Object value = null;
try {
value = prop.getValue ();
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// problem getting value => ignore this property
continue;
}
String valueType = prop.getValueType ().getName ();
String encodedValue = encodePrimitiveValue (value);
if (encodedValue == null) {
encodedValue = encodeValue (value);
}
if (encodedValue == null) {
// [PENDING - notify problem?]
continue;
}
//System.out.println("saving name="+prop.getName ()+", value="+value); // NOI18N
buf.append (indent);
addLeafElementOpenAttr (
buf,
XML_SYNTHETIC_PROPERTY,
new String[] {
ATTR_PROPERTY_NAME,
ATTR_PROPERTY_TYPE,
ATTR_PROPERTY_VALUE,
},
new String[] {
prop.getName (),
valueType,
encodedValue,
}
);
}
}
private void saveEvents (Hashtable events, StringBuffer buf, String indent) {
for (Iterator it = events.keySet ().iterator (); it.hasNext (); ) {
String eventName = (String)it.next ();
String handlerName = (String)events.get (eventName);
buf.append (indent);
addLeafElementOpenAttr (
buf,
XML_EVENT,
new String[] {
ATTR_EVENT_NAME,
ATTR_EVENT_HANDLER
},
new String[] {
eventName,
handlerName,
}
);
}
}
private void saveAuxValues (Map auxValues, StringBuffer buf, String indent) {
for (Iterator it = auxValues.keySet ().iterator (); it.hasNext (); ) {
String valueName = (String) it.next ();
Object value = auxValues.get (valueName);
if (value == null) continue; // such values are not saved
String valueType = value.getClass ().getName ();
String encodedValue = encodePrimitiveValue (value);
if (encodedValue == null) {
encodedValue = encodeValue (value);
}
if (encodedValue == null) {
// [PENDING - solve problem?]
continue;
}
buf.append (indent);
addLeafElementOpenAttr (
buf,
XML_AUX_VALUE,
new String[] {
ATTR_AUX_NAME,
ATTR_AUX_VALUE_TYPE,
ATTR_AUX_VALUE },
new String[] {
valueName,
valueType,
encodedValue
}
);
}
}
private void saveConstraints (RADVisualComponent component, StringBuffer buf, String indent) {
Map constraintsMap = component.getConstraintsMap ();
for (Iterator it = constraintsMap.keySet ().iterator (); it.hasNext (); ) {
String layoutName = (String)it.next ();
DesignLayout.ConstraintsDescription cd = (DesignLayout.ConstraintsDescription)constraintsMap.get (layoutName);
org.w3c.dom.Node constrNode = cd.storeToXML (topDocument);
if (constrNode != null) {
buf.append (indent);
addElementOpenAttr (
buf,
XML_CONSTRAINT,
new String[] {
ATTR_CONSTRAINT_LAYOUT,
ATTR_CONSTRAINT_VALUE
},
new String[] {
layoutName,
cd.getClass ().getName (),
}
);
saveNodeIntoText (buf, constrNode, indent + ONE_INDENT);
buf.append (indent);
addElementClose (
buf,
XML_CONSTRAINT
);
} else {
buf.append (indent);
addLeafElementOpenAttr (
buf,
XML_CONSTRAINT,
new String[] {
ATTR_CONSTRAINT_LAYOUT,
ATTR_CONSTRAINT_VALUE
},
new String[] {
layoutName,
cd.getClass ().getName (),
}
);
}
}
}
// --------------------------------------------------------------------------------------
// Value encoding methods
/** Obtains value from given propertyNode for specified RADComponent.
* @param propertyNode XML node where the property is stored
* @param radComponent the RADComponent of which the property is to be loaded
* @return the property value decoded from the node
*/
private Object getEncodedPropertyValue (org.w3c.dom.Node propertyNode, RADComponent radComponent)
throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException
{
org.w3c.dom.NamedNodeMap attrs = propertyNode.getAttributes ();
if (attrs == null) {
throw new IOException (); // [PENDING - explanation of problem]
}
org.w3c.dom.Node nameNode = attrs.getNamedItem (ATTR_PROPERTY_NAME);
org.w3c.dom.Node typeNode = attrs.getNamedItem (ATTR_PROPERTY_TYPE);
org.w3c.dom.Node editorNode = attrs.getNamedItem (ATTR_PROPERTY_EDITOR);
org.w3c.dom.Node valueNode = attrs.getNamedItem (ATTR_PROPERTY_VALUE);
org.w3c.dom.Node preCodeNode = attrs.getNamedItem (ATTR_PROPERTY_PRE_CODE);
org.w3c.dom.Node postCodeNode = attrs.getNamedItem (ATTR_PROPERTY_POST_CODE);
if (nameNode == null) {
throw new IOException (); // [PENDING - explanation of problem]
}
RADComponent.RADProperty prop = null;
if (radComponent != null) prop = radComponent.getPropertyByName (nameNode.getNodeValue ());
if (typeNode == null) {
if ((preCodeNode == null) || (postCodeNode == null)) {
throw new IOException (); // [PENDING - explanation of problem]
} else {
if (preCodeNode != null) {
prop.setPreCode (preCodeNode.getNodeValue ());
}
if (postCodeNode != null) {
prop.setPostCode (postCodeNode.getNodeValue ());
}
}
return NO_VALUE; // value is not stored for this property, just the pre/post code
}
Class propertyType = findPropertyType (typeNode.getNodeValue ());
PropertyEditor ed = null;
if (editorNode != null) {
Class editorClass = loadClass (editorNode.getNodeValue ());
if (prop != null) {
ed = FormEditor.createPropertyEditor (editorClass, propertyType, radComponent, prop);
} else {
if (Boolean.getBoolean ("netbeans.debug.form")) { // NOI18N
System.out.println ("Property: "+nameNode.getNodeValue ()+", of component: "+radComponent.getName ()+"["+radComponent.getBeanClass ().getName ()+"] not found."); // NOI18N
} // [PENDING better notification, localize]
}
}
Object value = null;
if (prop != null) {
if (preCodeNode != null) {
prop.setPreCode (preCodeNode.getNodeValue ());
}
if (postCodeNode != null) {
prop.setPostCode (postCodeNode.getNodeValue ());
}
}
if (valueNode != null) {
try {
value = decodePrimitiveValue (valueNode.getNodeValue (), propertyType);
} catch (IllegalArgumentException e) {
value = null; // should not happen
}
} else {
if ((ed != null) && (ed instanceof XMLPropertyEditor)) {
org.w3c.dom.NodeList propChildren = propertyNode.getChildNodes ();
if ((propChildren != null) && (propChildren.getLength () > 0)) {
// for forward compatibility - to be able to read props that support XML now
// but were saved in past when class did not support XML
boolean isXMLSerialized = false;
for (int i = 0; i < propChildren.getLength (); i++) {
if (XML_SERIALIZED_PROPERTY_VALUE.equals (propChildren.item (i).getNodeName ())) {
isXMLSerialized = true;
String serValue = findAttribute (propChildren.item (i), ATTR_PROPERTY_VALUE);
if (serValue != null) {
value = decodeValue (serValue);
}
break;
}
}
if (!isXMLSerialized) {
for (int i = 0; i < propChildren.getLength (); i++) {
if (propChildren.item (i).getNodeType () == org.w3c.dom.Node.ELEMENT_NODE) {
((XMLPropertyEditor)ed).readFromXML (propChildren.item (i));
value = ed.getValue ();
break;
}
}
}
}
} else {
org.w3c.dom.NodeList propChildren = propertyNode.getChildNodes ();
if ((propChildren != null) && (propChildren.getLength () > 0)) {
for (int i = 0; i < propChildren.getLength (); i++) {
if (XML_SERIALIZED_PROPERTY_VALUE.equals (propChildren.item (i).getNodeName ())) {
String serValue = findAttribute (propChildren.item (i), ATTR_PROPERTY_VALUE);
if (serValue != null) {
value = decodeValue (serValue);
}
break;
}
}
}
}
}
return value;
}
private Class findPropertyType (String type) throws ClassNotFoundException {
if ("int".equals (type)) return Integer.TYPE; // NOI18N
else if ("short".equals (type)) return Short.TYPE; // NOI18N
else if ("byte".equals (type)) return Byte.TYPE; // NOI18N
else if ("long".equals (type)) return Long.TYPE; // NOI18N
else if ("float".equals (type)) return Float.TYPE; // NOI18N
else if ("double".equals (type)) return Double.TYPE; // NOI18N
else if ("boolean".equals (type)) return Boolean.TYPE; // NOI18N
else if ("char".equals (type)) return Character.TYPE; // NOI18N
else {
return loadClass (type);
}
}
/** Decodes a value of given type from the specified String. Supported types are: <UL>
* <LI> RADConnectionPropertyEditor.RADConnectionDesignValue
* <LI> Class
* <LI> String
* <LI> Integer, Short, Byte, Long, Float, Double, Boolean, Character </UL>
* @return decoded value
* @exception IllegalArgumentException thrown if specified object is not of supported type
*/
private Object decodePrimitiveValue (String encoded, Class type) throws IllegalArgumentException{
if ("null".equals (encoded)) return null; // NOI18N
if (Integer.class.isAssignableFrom (type) || Integer.TYPE.equals (type)) {
return Integer.valueOf (encoded);
} else if (Short.class.isAssignableFrom (type) || Short.TYPE.equals (type)) {
return Short.valueOf (encoded);
} else if (Byte.class.isAssignableFrom (type) || Byte.TYPE.equals (type)) {
return Byte.valueOf (encoded);
} else if (Long.class.isAssignableFrom (type) || Long.TYPE.equals (type)) {
return Long.valueOf (encoded);
} else if (Float.class.isAssignableFrom (type) || Float.TYPE.equals (type)) {
return Float.valueOf (encoded);
} else if (Double.class.isAssignableFrom (type) || Double.TYPE.equals (type)) {
return Double.valueOf (encoded);
} else if (Boolean.class.isAssignableFrom (type) || Boolean.TYPE.equals (type)) {
return Boolean.valueOf (encoded);
} else if (Character.class.isAssignableFrom (type) || Character.TYPE.equals (type)) {
return new Character (encoded.charAt(0));
} else if (String.class.isAssignableFrom (type)) {
return encoded;
} else if (Class.class.isAssignableFrom (type)) {
try {
return loadClass (encoded);
} catch (ClassNotFoundException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// will return null as the notification of failure
}
}
throw new IllegalArgumentException ();
}
/** Encodes specified value into a String. Supported types are: <UL>
* <LI> Class
* <LI> String
* <LI> Integer, Short, Byte, Long, Float, Double, Boolean, Character </UL>
* @return String containing encoded value or null if specified object is not of supported type
*/
private String encodePrimitiveValue (Object value) {
if ((value instanceof Integer) ||
(value instanceof Short) ||
(value instanceof Byte) ||
(value instanceof Long) ||
(value instanceof Float) ||
(value instanceof Double) ||
(value instanceof Boolean) ||
(value instanceof Character)) {
return value.toString ();
}
if (value instanceof String) {
return (String)value;
}
if (value instanceof Class) {
return ((Class)value).getName ();
}
if (value == null) {
return "null"; // NOI18N
}
return null; // is not a primitive type
}
/** Decodes a value of from the specified String containing textual representation of serialized stream.
* @return decoded object
* @exception IOException thrown if an error occures during deserializing the object
*/
public static Object decodeValue (String value) throws IOException {
if ((value == null) || (value.length () == 0)) return null;
char[] bisChars = value.toCharArray ();
byte[] bytes = new byte[bisChars.length];
String singleNum = ""; // NOI18N
int count = 0;
for (int i = 0; i < bisChars.length; i++) {
if (',' == bisChars[i]) {
try {
bytes[count++] = Byte.parseByte (singleNum);
} catch (NumberFormatException e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
throw new IOException ();
}
singleNum = ""; // NOI18N
} else {
singleNum += bisChars[i];
}
}
// add the last byte
bytes[count++] = Byte.parseByte (singleNum);
ByteArrayInputStream bis = new ByteArrayInputStream (bytes, 0, count);
try {
ObjectInputStream ois = new org.openide.util.io.NbObjectInputStream (bis);
Object ret = ois.readObject ();
return ret;
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
throw new IOException ();
}
}
/** Encodes specified value to a String containing textual representation of serialized stream.
* @return String containing textual representation of the serialized object
*/
public static String encodeValue (Object value) {
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
try {
ObjectOutputStream oos = new ObjectOutputStream (bos);
oos.writeObject (value);
oos.close ();
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
return null; // problem during serialization
}
byte[] bosBytes = bos.toByteArray ();
StringBuffer sb = new StringBuffer (bosBytes.length);
for (int i = 0; i < bosBytes.length; i++) {
if (i != bosBytes.length - 1) {
sb.append (bosBytes[i]+","); // NOI18N
} else {
sb.append (""+bosBytes[i]); // NOI18N
}
}
return sb.toString ();
}
// --------------------------------------------------------------------------------------
// Utility formatting methods
private void addElementOpen (StringBuffer buf, String elementName) {
buf.append ("<"); // NOI18N
buf.append (elementName);
buf.append (">\n"); // NOI18N
}
private void addElementOpenAttr (StringBuffer buf, String elementName, String[] attrNames, String[] attrValues) {
buf.append ("<"); // NOI18N
buf.append (elementName);
for (int i = 0; i < attrNames.length; i++) {
if (attrValues[i] == null) continue;
buf.append (" "); // NOI18N
buf.append (attrNames[i]);
buf.append ("=\""); // NOI18N
buf.append (encodeToProperXML(attrValues[i]));
buf.append ("\""); // NOI18N
}
buf.append (">\n"); // NOI18N
}
private void addLeafElementOpenAttr (StringBuffer buf, String elementName, String[] attrNames, String[] attrValues) {
buf.append ("<"); // NOI18N
buf.append (elementName);
for (int i = 0; i < attrNames.length; i++) {
if (attrValues[i] == null) continue;
buf.append (" "); // NOI18N
buf.append (attrNames[i]);
buf.append ("=\""); // NOI18N
buf.append (encodeToProperXML(attrValues[i]));
buf.append ("\""); // NOI18N
}
buf.append ("/>\n"); // NOI18N
}
private void addElementClose (StringBuffer buf, String elementName) {
buf.append ("</"); // NOI18N
buf.append (elementName);
buf.append (">\n"); // NOI18N
}
private void saveNodeIntoText (StringBuffer buf, org.w3c.dom.Node valueNode, String indent) {
buf.append (indent);
buf.append ("<"); // NOI18N
buf.append (valueNode.getNodeName ());
org.w3c.dom.NamedNodeMap attributes = valueNode.getAttributes ();
if (attributes != null) {
ArrayList attribList = new ArrayList (attributes.getLength ());
for (int i = 0; i < attributes.getLength (); i++) {
attribList.add (attributes.item (i));
}
// sort the attributes by attribute name
// probably not necessary, but there is no guarantee that
// the order of attributes will remain the same in DOM
Collections.sort (attribList, new Comparator () {
public int compare(Object o1, Object o2) {
org.w3c.dom.Node n1 = (org.w3c.dom.Node)o1;
org.w3c.dom.Node n2 = (org.w3c.dom.Node)o2;
return n1.getNodeName ().compareTo (n2.getNodeName ());
}
}
);
for (Iterator it = attribList.iterator (); it.hasNext ();) {
org.w3c.dom.Node attrNode = (org.w3c.dom.Node)it.next ();
String attrName = attrNode.getNodeName ();
String attrValue = attrNode.getNodeValue ();
buf.append (" "); // NOI18N
buf.append (encodeToProperXML (attrName));
buf.append ("=\""); // NOI18N
buf.append (encodeToProperXML (attrValue));
buf.append ("\""); // NOI18N
}
}
// [PENDING - CNODES, TEXT NODES, ...]
org.w3c.dom.NodeList children = valueNode.getChildNodes ();
if ((children == null) || (children.getLength () == 0)) {
buf.append ("/>\n"); // NOI18N
} else {
buf.append (">\n"); // NOI18N
for (int i = 0; i < children.getLength (); i++) {
if (children.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
saveNodeIntoText (buf, children.item (i), indent + ONE_INDENT);
}
buf.append (indent);
buf.append ("</"); // NOI18N
buf.append (encodeToProperXML (valueNode.getNodeName ()));
buf.append (">\n"); // NOI18N
}
}
// --------------------------------------------------------------------------------------
// Utility DOM access methods
/* private void walkTree (org.w3c.dom.Node node, String indent) {
if (node.getNodeType () == org.w3c.dom.Node.TEXT_NODE) return; // ignore text nodes
System.out.println (indent + node.getNodeName ());
org.w3c.dom.NamedNodeMap attrs = node.getAttributes ();
if (attrs != null) {
for (int i = 0; i < attrs.getLength (); i++) {
org.w3c.dom.Node attr = attrs.item(i);
System.out.println (indent + " Attribute: "+ attr.getNodeName ()+", value: "+attr.getNodeValue ());
}
}
org.w3c.dom.NodeList children = node.getChildNodes ();
if (children != null) {
for (int i = 0; i < children.getLength (); i++) {
walkTree (children.item (i), indent + " ");
}
}
}
*/
private String encodeToProperXML (String text) {
if (text.indexOf ('&') != -1) text = Utilities.replaceString (text, "&", "&"); // must be the first to prevent changes in the &XX; codes // NOI18N
if (text.indexOf ('<') != -1) text = Utilities.replaceString (text, "<", "<"); // NOI18N
if (text.indexOf ('>') != -1) text = Utilities.replaceString (text, ">", ">"); // NOI18N
if (text.indexOf ('\'') != -1) text = Utilities.replaceString (text, "\'", "'"); // NOI18N
if (text.indexOf ('\"') != -1) text = Utilities.replaceString (text, "\"", """); // NOI18N
if (text.indexOf ('\n') != -1) text = Utilities.replaceString (text, "\n", "
"); // NOI18N
if (text.indexOf ('\t') != -1) text = Utilities.replaceString (text, "\t", " "); // NOI18N
return text;
}
/** Finds first subnode of given node with specified name.
* @param node the node whose subnode we are looking for
* @param name requested name of the subnode
* @return the found subnode or null if no such subnode exists
*/
private org.w3c.dom.Node findSubNode (org.w3c.dom.Node node, String name) {
org.w3c.dom.NodeList children = node.getChildNodes ();
if (children != null) {
for (int i = 0; i < children.getLength (); i++) {
if (children.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (name.equals (children.item (i).getNodeName ())) {
return children.item (i);
}
}
}
return null;
}
/** Finds all subnodes of given node with specified name.
* @param node the node whose subnode we are looking for
* @param name requested name of the subnode
* @return array of the found subnodes
*/
private org.w3c.dom.Node[] findSubNodes (org.w3c.dom.Node node, String name) {
ArrayList list = new ArrayList ();
org.w3c.dom.NodeList children = node.getChildNodes ();
if (children != null) {
for (int i = 0; i < children.getLength (); i++) {
if (children.item (i).getNodeType () == org.w3c.dom.Node.TEXT_NODE) continue; // ignore text nodes
if (name.equals (children.item (i).getNodeName ())) {
list.add (children.item (i));
}
}
}
return (org.w3c.dom.Node[]) list.toArray (new org.w3c.dom.Node[list.size ()]);
}
/** Utility method to obtain given attribute value from specified Node.
* @return attribute name or null if the attribute is not present
*/
private String findAttribute (org.w3c.dom.Node node, String attributeName) {
org.w3c.dom.NamedNodeMap attributes = node.getAttributes ();
org.w3c.dom.Node valueNode = attributes.getNamedItem (attributeName);
if (valueNode == null) return null;
else return valueNode.getNodeValue ();
}
/** Loads a class. First it mangles its name */
static Class loadClass(String clazz) throws ClassNotFoundException {
return TopManager.getDefault().currentClassLoader().loadClass(Utilities.translate(clazz));
}
}
/*
* Log
* 50 Gandalf-post-FCS1.47.1.1 4/14/00 Jesse Glick Trung's package renaming
* compatibility code.
* 49 Gandalf-post-FCS1.47.1.0 3/20/00 Tran Duc Trung FIX: wrong form
* character encoding can lead to form data loss
* 48 Gandalf 1.47 1/13/00 Ian Formanek NOI18N #2
* 47 Gandalf 1.46 1/5/00 Ian Formanek NOI18N
* 46 Gandalf 1.45 1/2/00 Ian Formanek Improved serialization
* of primitive types in AUX values and Synthetic properties
* 45 Gandalf 1.44 12/14/99 Pavel Buzek #1991
* 44 Gandalf 1.43 12/9/99 Pavel Buzek reading propertied that
* support XML but were serialized in older beta version
* 43 Gandalf 1.42 11/24/99 Pavel Buzek decodeValue and
* encodeValue made public and static to be used as utility methods
* 42 Gandalf 1.41 11/16/99 Pavel Buzek recognition of XML file
* encoding improved
* 41 Gandalf 1.40 11/15/99 Pavel Buzek
* 40 Gandalf 1.39 11/15/99 Pavel Buzek property for encoding
* 39 Gandalf 1.38 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 38 Gandalf 1.37 10/6/99 Ian Formanek Fixed bug 4199 -
* Pre/Post initializer code not added to source code unless property
* editor that spawns Pre/Post code editor has something changed.
* 37 Gandalf 1.36 9/30/99 Ian Formanek reflecting XML changes
* 36 Gandalf 1.35 9/24/99 Ian Formanek New system of changed
* properties in RADComponent - Fixes bug 3584 - Form Editor should try to
* enforce more order in the XML elements in .form.
* 35 Gandalf 1.34 9/15/99 Ian Formanek Fixes bug introduced in
* Build 388, which caused layouts not to save their properties, improved
* errors notification
* 34 Gandalf 1.33 9/14/99 Ian Formanek RADProperty pre/postCode
* is persistent
* 33 Gandalf 1.32 9/14/99 Ian Formanek Fixed bug 3287 - Form
* Editor does not correctly reload forms with multi-line String property
* values.
* 32 Gandalf 1.31 9/14/99 Ian Formanek Fixed bug 3564 - Form
* editor cannot load forms with non-US characters.
* 31 Gandalf 1.30 9/12/99 Ian Formanek FormAwareEditor.setRADComponent
* changes
* 30 Gandalf 1.29 9/7/99 Ian Formanek Errors notification
* during form load changed
* 29 Gandalf 1.28 9/2/99 Ian Formanek Fixed bug 3696 - When
* connection is copied and pasted into form, the initialization code of
* the ConnectionSource component is not correctly generated. and 3695 -
* Modified properties with null value are not restored correctly when a
* form is reloaded.
* 28 Gandalf 1.27 8/19/99 Ian Formanek No semantic change
* 27 Gandalf 1.26 8/9/99 Ian Formanek Used currentClassLoader
* to fix problems with loading beans only present in repository
* 26 Gandalf 1.25 8/6/99 Ian Formanek Survives when storeToXML
* returns null
* 25 Gandalf 1.24 8/6/99 Ian Formanek displaying error log
* 24 Gandalf 1.23 8/2/99 Ian Formanek NonVisuals element is
* not saved if empty
* 23 Gandalf 1.22 8/2/99 Ian Formanek Proper encoding of
* special characters into XML (<, >, ", ', &)
* 22 Gandalf 1.21 8/1/99 Ian Formanek Really does what last
* checkin should have done
* 21 Gandalf 1.20 8/1/99 Ian Formanek Improved creation of
* property editors, removed debug messages
* 20 Gandalf 1.19 7/25/99 Ian Formanek Variables management
* moved to RADComponent
* 19 Gandalf 1.18 7/23/99 Ian Formanek Works with
* RADConnectionPropertyEditor
* 18 Gandalf 1.17 7/20/99 Ian Formanek Persistence of menus
* 17 Gandalf 1.16 7/18/99 Ian Formanek More correct handling of
* errors during loading form
* 16 Gandalf 1.15 7/14/99 Ian Formanek Fixed saveNodeIntoText
* method
* 15 Gandalf 1.14 7/13/99 Ian Formanek Constraints persistence
* added
* 14 Gandalf 1.13 7/13/99 Ian Formanek Third draft
* 13 Gandalf 1.12 7/12/99 Ian Formanek Uses XMLPropertyEditor
* or sub element for serialized property values
* 12 Gandalf 1.11 7/12/99 Ian Formanek Second cut - loads/saves
* events, properties and aux values
* 11 Gandalf 1.10 7/12/99 Ian Formanek First cut of saving
* 10 Gandalf 1.9 7/11/99 Ian Formanek hex encoding is 2-char
* for all bytes
* 9 Gandalf 1.8 7/11/99 Ian Formanek
* 8 Gandalf 1.7 7/8/99 Ian Formanek
* 7 Gandalf 1.6 7/5/99 Ian Formanek getComponentInstance->getBeanInstance,
* getComponentClass->getBeanClass
* 6 Gandalf 1.5 6/30/99 Ian Formanek Second draft of XML
* Serialization
* 5 Gandalf 1.4 6/28/99 Ian Formanek First cut of XML
* persistence
* 4 Gandalf 1.3 6/24/99 Ian Formanek
* 3 Gandalf 1.2 6/9/99 Ian Formanek ---- Package Change To
* org.openide ----
* 2 Gandalf 1.1 6/7/99 Ian Formanek
* 1 Gandalf 1.0 5/30/99 Ian Formanek
* $
*/